The speed and efficiency of many computing applications depend in large part upon the availability of processing resources. To this end, computing architectures commonly incorporate multithreaded processes that enable sharing of resources. Such threading can accommodate multiple paths of execution within a computer/operating system. As such, a thread may be characterized as a separately executable portion of a process. Each thread typically has its own distinct program counter and represents a separate movement of a processor through program instruction space and storage. In this manner, a program may be broken-up into multiple different threads. Ideally, this segmentation avoids requiring a computer process to execute a single unitary process or program from start to finish with pronounced intervals of wasted processing time. As such, a thread continuously accesses a resource until either its execution is interrupted or that thread must wait for a resource it requires to become available.
To facilitate coordination of threads and associated resources, threads typically share a priority scheme or schedule that partially dictates allocation of processing cycles as between different threads. A task dispatcher program may use this scheme to assign and dispatch a central processing unit(s) (CPU), timeslice, or other resource to each thread. Such exemplary resources might include hardware registers, database files and other memory resources. Thus, multithreaded operation can provide the illusion of simultaneous execution of multiple programs, given the relatively high processing speeds relative to that of other resources in the computer.
However, despite the flexibility afforded by multithreaded systems, complications associated with resource allocation persist. Some such obstacles arise from the dynamic, intertwined processing requirements of operating systems. Namely, while each thread of an operating system may have access to the same resource at one time or another, only one thread can access the resource at a time. This provision is termed “serialization” and can prevent operating errors, such as two threads incrementing a counter out of sequence. Consequently, access to resources for many threads may be premised upon the prior execution of others. Such dependency may introduce its own complexity and inefficiency into a processing application. Compounded over multiple processing layers and iterations, thread inactivity translates into slow processing speeds due to wait periods.
A specific instance of such a wait time may occur where an accessing thread has locked access to a contentious resource to ensure its own exclusive processing. For instance, the thread may initiate a gate lock to prevent the task dispatcher from allowing access to another thread desiring the resource, thus satisfying the above discussed serialization requirement. As such, while one thread updates a resource, hundreds or thousands of others may wait for access. Such a lock may remain in force until a condition is met. Thus, the additional threads remain locked out of the resource by the operating system.
Exemplary conditions may include the thread accomplishing its task or being timed-out. A timed-out condition regards the task dispatcher removing a thread from a resource after the expiration of a predetermined duration. Once execution so ceases for a given thread, the computer system begins executing another thread then cued for execution through context switching.
While delays associated with contact switching may be relatively small as compared to the processing cycles that would otherwise be wasted during single task processing, advantages realized by multithreading have given rise to a demand for even greater efficiencies. To this end, inefficiencies associated with idle threads prompt programmers and network designers to minimize wait periods associated with the above discussed locks and context switching operations. Locating, analyzing and correcting suspected faults/contentious instances of a computer program is a process known as debugging.
One potential remedy for periods of excessive waiting may include shortening a path length to a resource, thereby decreasing associated processing cycles and time. Another solution may involve including multiple instances of a subroutine and/or resource throughout a system, increasing the accessibility of the contentious program function. Where a lock is attributable to a shortage of a hardware resources, the most feasible solution may involve integrating more hardware into the system. The inclusion of additional hardware may reduce the incidence of idle threads, facilitating more efficient utilization of CPU resources.
Implementing such solutions, however, presupposes the identification of contentious locking incidences. Locating a problematic task and/or resource can represent a daunting and painstaking undertaking for a programmer. To this end, debugging operations may utilize programs configured to assist the analysis of system processes. For example, a designer may rely on a task switch trace program to record switching occurrences relating to a particular thread. A task switch trace program creates a comprehensive history of all transition sequences relating to the thread.
Transitions tracked by the task switch trace program may include every incidence of where execution of a thread was halted. The task switch trace program generally responds to each transition occurrence by recording the time of a halting occurrence within a database exclusive to the thread. Due to the exhaustive volume of such occurrences that are typically associated with a single thread, the database populated by the task switch trace program may require substantial storage space. Such storage requirements can severely burden available resources of most systems if used with any frequency.
As such, databases generated by the task switch trace program may only be run for very short periods due to the large amount of data recorded by the program. The selective operation of the program further handicaps their usefulness with regard to program evaluation processing. For instance, the relatively short duration of coverage associated with the task switch trace program may be preclusive for applications that require more comprehensive analysis. That is, the task switch program may be limited to detecting transition occurrences coincident with its relatively narrow window of operation. As such, the tool may fail to assist the programmer in pinpointing a contentious event in a typical, moderately sized program.
The voluminous nature of the database generated by the task switch trace program further compounds efforts of programmers to efficiently analyze programs. The volume associated with a typical database can be overwhelming and largely superfluous to programmers faced with the meticulous and often tedious task of troubleshooting a program. Consequently, inefficient and problematic portions of a program may remain overlooked. As a related matter, a programmer utilizing a task switch trace program may be unable to employ the program in a dynamic fashion. A user is typically relegated to evaluating the programmatically constructed database only after the task switch trace has populated it in its entirety. As such, the programmer may be unable to view potential bottlenecks and other transition occurrences as they develop. Thus, the programmer is relegated to reconstructing the contentious sequence after viewing the entire database.
Consequently, what is needed is a more efficient and effective manner of analyzing program and system inefficiencies within a multithreaded environment.